/**
 * 闭包捕获和处理环境中的值的方式会影响闭包实现哪些 trait，
 * 而 trait 是函数和结构体指定它们可以使用哪些类型闭包的方式。根据闭包体如何处理这些值，闭包会自动、渐进地实现一个、两个或全部三个 Fn trait。
 *  FnOnce 适用于只能被调用一次的闭包。所有闭包至少都实现了这个 trait，因为所有闭包都能被调用。
 *         一个会将捕获的值从闭包体中移出的闭包只会实现 FnOnce trait，而不会实现其他 Fn 相关的 trait，因为它只能被调用一次。
    FnMut  适用于不会将捕获的值移出闭包体，但可能会修改捕获值的闭包。这类闭包可以被调用多次。
    Fn     适用于既不将捕获的值移出闭包体，也不修改捕获值的闭包，同时也包括不从环境中捕获任何值的闭包。
           这类闭包可以被多次调用而不会改变其环境，这在会多次并发调用闭包的场景中十分重要。
    注意，这个是自动的，或者说是编译器自动处理的。不需要手动实现。

    一旦实现了FnMut或者Fn，那么被捕获的变量在父级作用域内就消失了，再调用这些父级变量就会报告编译错误：value borrowed here after move


    总结：
    如果是不可变引用，那么可以在父级作用域内随意使用；
    如果是可变引用，那么在父级领域中，在匿名函数被调用前，不可引用（使用)
    如果是移动了所有全，自然在父级作用域不可使用
*/
fn main() {
    let x = 10;

    // 1. 没有捕获
    let closure1 = |y| x + y;
    println!("1.0执行前x={}", x); //x是不可变引用，所以x可以在父级作用域不停使用
    let x1=closure1(10);
    println!("1.0现在{}+{}={},x还是{}", x,10,x1,x); //x是不可变引用，所以x可以在父级作用域不停使用

    // 1.5 捕获，但是不变
    let f = |x| { println!("不改变捕获的x={}", x) };
    println!("1.5执行前x={}", x); //x是不可变引用，所以x可以在父级作用域不停使用
    f(x);
    println!("1.5现在x={}", x); //x是不可变引用，所以x可以在父级作用域不停使用

    //2.0 可变捕获
    let mut z = 20;

    println!("2.0执行前，z={}", z);
    // 可变捕获，实现FnMut
    let mut closure2 = || {
        z += 1;
    };
    closure2();
    //println!("第一次调用后，z={}", z);   //编译错误 immutable borrow occurs here
    closure2();
    println!("2.0第二次调用后，z={}", z);

    // 3.0 所有权转移的可变捕获
    let mut vec = vec![1, 2, 3];

    println!("3.0执行前，vec={:?}", vec);
    // 所有权转移，只实现FnOnce
    let mut closure3 = move || {
        vec.push(4);
        println!("{:?}", vec);
    };

    closure3();
    //println!("现在vec={:?}", vec);  //编译错误，因为被closure3借用后，vec已经不在范围之内（消失了);
    closure3();
    
    //println!("{:?}", vec);  这里不能再使用vec,因为vec已经被move到closure3中了
    let  fx=|y| y+1;
    let v=20;
    let r=fx(v);
    println!("{}+1={}",v,r);
}
